﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Text.RegularExpressions;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

using ProjectBase.Core;

using Survey.Common;
using Survey.Common.Validation;

namespace Survey.Business
{
    public class RegularExpressionRule<TItem> : RuleBase, IValidationRule<TItem>
        where TItem : class
    {
        #region members
        private readonly Func<TItem, string> _compiledExpression;
        string _propertyName;
        string _regularExpression;
        bool _isValidWhenMatch = true;
        string _errorMessage = Str.Messages.FilterRegularExpressionMessage3;

        #endregion members

        #region Constructor
        public RegularExpressionRule(Expression<Func<TItem, string>> expression, string regularExpression)
        {
            Contract.Requires(expression.Is());
            Contract.Requires(regularExpression.IsNotEmpty());

            var body = expression.Body as MemberExpression;
            if (body.IsNull())
            {
                throw new NotSupportedException(
                    "Provided 'Expression<Func<TITem, string>>' must be of a 'ExpressionType.MemberAccess' (RegularExpressionRule). ");
            }

            _regularExpression = regularExpression;
            _propertyName = body.Member.Name;
            _compiledExpression = expression.Compile();
        }
        #endregion Constructor

        #region Validate

        public virtual ValidationResult Validate(TItem item, out ValidationMessage message)
        {
            message = null;

            // item cannot be null
            if (item.IsNull())
            {
                message = new ValidationMessage(Str.Messages.NullInsteadOfEntityProvided1)
                {
                    EntityName,
                };
                return ValidationResult.Error;
            }

            var result = CompiledExpression.Invoke(item);

            if (result.IsEmpty()
                || RegularExpression.IsEmpty())
            {
                message = new ValidationMessage("CheckRegularExpressionNeedsValueAndExpression");
                return ValidationResult.Error;
            }

            var strict = new Regex(RegularExpression);
            var isMatch = strict.IsMatch(result) == IsValidWhenMatch;
            if (!isMatch)
            {
                message = new ValidationMessage(ErrorMessage)
                {
                    result,
                    PropertyName,
                    RegularExpression,
                };
                return ValidationResult.Error;
            }
            return ValidationResult.IsValid;
        }

        #endregion Validate

        #region fluent

        public virtual RegularExpressionRule<TItem> AsRequired()
        {
            IsRequired = true;
            return this;
        }

        public virtual RegularExpressionRule<TItem> NotMatchIsValid()
        {
            IsValidWhenMatch = false;
            return this;
        }

        /// <summary>Custom error message filled with 3 arguments: propertyValue, propertyName, regularExpression</summary>
        public virtual RegularExpressionRule<TItem> UseCustomErrorMessage(string errorMessage)
        {
            _errorMessage = errorMessage;
            return this;
        }

        #endregion fluent

        #region Client

        public override string GetClientRule(string prefix = null)
        {
            var rule = string.Empty;
            // TODO
            return rule;
        }

        #endregion Client

        #region properties
        protected virtual Func<TItem, string> CompiledExpression
        {
            get { return _compiledExpression; }
        }
        protected virtual bool IsValidWhenMatch
        {
            get { return _isValidWhenMatch; }
            set { _isValidWhenMatch = value; }
        }

        protected virtual bool IsRequired { get; set; }
        protected virtual string PropertyName
        {
            get { return _propertyName; }
            set { _propertyName = value; }
        }
        protected virtual string EntityName { get { return typeof(TItem).Name; } }
        protected virtual string RegularExpression
        {
            get { return _regularExpression; }
            set { _regularExpression = value; }
        }
        protected virtual string ErrorMessage
        {
            get { return _errorMessage; }
            set { _errorMessage = value; }
        }

        #endregion properties
    }
}